#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Time.h>
#include <Timezone.h>
#include <SPI.h>
#include <Adafruit_ssd1306syp.h>
#include <CN_SSD1306.h>
#include "NTP.h"
#include <ArduinoJson.h>

#define MQTT_VERSION 3.1.1

#define WIFI_SSID "xxxxxxxx"           // 使用时请修改为当前你的 wifi ssid
#define WIFI_PASSWORD "xxxxxxxx"       // 使用时请修改为当前你的 wifi 密码

#define MQTT_CLIENT_ID  "Door1"        //用户ID
#define MQTT_SERVER_IP  "0.0.0.0"      // MQTT服务器
#define MQTT_SERVER_PORT  1883         // 端口号
#define MQTT_USER  "pi"                // 用户名
#define MQTT_PASSWORD  "raspberry"     // 密码

#define MQTT_SENSOR_TOPIC  "home/sensor/door/1"    //主题

#define SLEEPING_TIME_IN_SECONDS  600; // 10分钟（600秒）

#define DOOR     2                     //门窗传感器接口
//根据液晶接口类型来配置端口
#define SDA_PIN 12
#define SCL_PIN 14
Adafruit_ssd1306syp display(SDA_PIN, SCL_PIN);
CN_SSD1306 lucky(SDA_PIN, SCL_PIN);

// 北京时间时区
#define STD_TIMEZONE_OFFSET +8   

//定义为中国
TimeChangeRule mySTD = {"", First,  Sun, Jan, 0, STD_TIMEZONE_OFFSET * 60};
Timezone myTZ(mySTD, mySTD);

unsigned long prevTime;
long interval = 2000; //(ms) - 2 秒发送一次

//WiFiClient client;
WiFiClient wifiClient;
PubSubClient client(wifiClient, MQTT_SERVER_IP, MQTT_SERVER_PORT);
//这个函数一秒钟调用一次
void updateDisplay(void) {
  TimeChangeRule *tcr;                          //指向时间变化规则的指针
  time_t utc = now();                           // 从NTP提供者读取当前UTC时间
  time_t localTime = myTZ.toLocal(utc, &tcr);   // 将DST转换为本地时间
  // 将时间转换为年月日时分秒
  int weekdays =   weekday(localTime);
  int days    =   day(localTime);
  int months  =   month(localTime);
  int years   =   year(localTime);
  int seconds =   second(localTime);
  int minutes =   minute(localTime);
  int hours   =   hour(localTime) ;   //采用12小时格式则使用 hourFormat12(localTime) isPM()/isAM()

  display.setTextSize(1);             //设置字体大小
  display.setTextColor(WHITE);        //设置字体颜色白色
  display.setCursor(3, 56);           //设置字体的起始位置
  display.print(years);
  display.print("/");
  if ( months < 10 ) {
    display.print(0);
    display.print(months);
  }
  if ( months >= 10 ) {
    display.print(months);
  }
  display.print("/");
  if ( days < 10 ) {
    display.print(0);
    display.print(days);
  }
  if ( days >= 10 ) {
    display.print(days);
  }
  display.print("  ");
  if ( hours < 10 ) {
    display.print(0);
    display.print(hours);
  }
  if ( hours >= 10 ) {
    display.print(hours);
  }
  display.print(":");
  if ( minutes < 10 ) {
    display.print(0);
    display.print(minutes);
  }
  if ( minutes >= 10 ) {
    display.print(minutes);
  }
  display.print(":");
  if ( seconds < 10 ) {
    display.print(0);
    display.print(seconds);
  }
  if ( seconds >= 10 ) {
    display.print(seconds);
  }
  display.update();                  //显示以上信息
  display.clear();                   //清屏
}
// function called to publish the lux
void publishData(String p_lux) {
  // 创建一个json对象
  // doc : https://github.com/bblanchon/ArduinoJson/wiki/API%20Reference
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  root["door"] = p_lux;
  root.prettyPrintTo(Serial);
  Serial.println("");
  char data[200];
  root.printTo(data, root.measureLength() + 1);
  client.publish(MQTT_SENSOR_TOPIC, data);
}
// 回传函数，此处为空
void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
}
// 连接MQTT服务器
void reconnect() {
    while (!client.connected()) {
    Serial.print("INFO: Attempting MQTT connection...");
    // 尝试连接
    if (client.connect(MQTT::Connect(MQTT_CLIENT_ID).set_keepalive(90).set_auth(MQTT_USER, MQTT_PASSWORD))) {
      Serial.println("INFO: connected");
    } else {
      Serial.print("ERROR: failed, rc=");
      Serial.println("DEBUG: try again in 5 seconds");
      // 等待5秒
      delay(5000);
    }
  }
}
void setup() {
  Serial.begin(115200);
  //设置端口为输入模式
  pinMode(DOOR,INPUT); 
  //连接网络
  Serial.println();
  Serial.println();
  Serial.print("INFO: Connecting to ");
  Serial.println(WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  initNTP(WIFI_SSID, WIFI_PASSWORD);
  Serial.println("");
  Serial.println("INFO: WiFi connected");
  Serial.println("INFO: IP address: ");
  Serial.println(WiFi.localIP());
 
  //初始化液晶
  display.initialize();
  delay(10);
  prevTime = 0;
}
// 定义一个前一秒的值
time_t previousSecond = 0;

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  int i;
  int n =digitalRead(DOOR);           //取出端口值
  
  if (prevTime + interval < millis() || prevTime == 0) {
    prevTime = millis();
    Serial.println("checking again");
    Serial.println(prevTime);
    //对值判断，高则显示开|低则关
    if( n == HIGH){            
      publishData("on");//Clear
      Serial.println("published environmental data");
    }
    if( n == LOW){
      publishData("off");//Detected
      Serial.println("published environmental data");
    }
    Serial.println("published environmental data");
  }
  delay(10);
  display.setTextSize(2);             
  display.setTextColor(WHITE);
  display.setCursor(14, 0);
  display.print("-ESP8266-");

  lucky.ShowCN(12, 4, 6); //Show Chinese
  lucky.ShowCN(28, 4, 7);
  lucky.ShowCN(44, 4, 8);
  lucky.ShowCN(60, 4, 9);
  lucky.ShowCN(76, 4, 4);
  //对值判断，高则显示开|低则关
  if( n == HIGH){                      
    lucky.ShowCN(96, 4, 10);
  }
  if( n == LOW){
    lucky.ShowCN(96, 4, 11);
  }
    
  delay(1000);
  //  仅当时间改变时才更新显示
  if (timeStatus() != timeNotSet) {
    if (second() != previousSecond) {
      previousSecond = second();
      // 更新显示
      updateDisplay();
    }
  }
}